package com.utopia.keyvalue.store.impl.disk;

import java.io.File;

import com.utopia.keyvalue.store.Configure;

/**
 * @author yanjiaqiang
 * @date 2011-3-16
 * @version $Id: IndexStore.java 5 2011-03-22 09:23:42Z JiaqiangYan@gmail.com $
 */
public class IndexStore {

	String indexFilePath = Configure.getDataBaseDir() + File.separator + "index" + Configure.INDEX_FILE_SUFFIX;
	File file = new File(indexFilePath);
	FileStore store = new FileStore(file, Configure.getIndexMemorySize());

	public IndexEntry put(String key, int datafileIndex, int datafilePosOffset) {
		IndexEntry index = findIndex(key);
		index.setAvailable(false);
		index.setOffset(offset(key));
		index.setKeyhash(hash(key));
		index.setDatafileIndex(datafileIndex);
		index.setDatafilePosOffset(datafilePosOffset);
		putIndex(index);
		return index;
	}

	public IndexEntry putIfAbent(String key, int datafileIndex, int datafilePosOffset) {
		IndexEntry index = findIndex(key);
		// 可用说明没有该key对应的Index
		if (index.isAvailable()) {
			index.setAvailable(false);
			index.setOffset(offset(key));
			index.setKeyhash(hash(key));
			index.setDatafileIndex(datafileIndex);
			index.setDatafilePosOffset(datafilePosOffset);
			putIndex(index);
		}
		return index;
	}

	private void putIndex(IndexEntry index) {
		store.put(index.getOffset(), index.toBytes());
	}

	/**
	 * 得到文件的指定的位置
	 * 
	 * @param key
	 * @return
	 */
	int offset(String key) {
		int hash = hash(key.hashCode());
		int startOffset = store.getStartOffset();
		// 将文件平均分成多个table，每个table存放100个数据
		int tables = (store.getFileSize() - startOffset) / (100 * IndexEntry.LENGTH);
		int table = hash % tables;
		return table * 100 * IndexEntry.LENGTH + startOffset;
	}

	int hash(String key) {
		return hash(key.hashCode());
	}

	static int hash(int h) {
		h ^= (h >>> 20) ^ (h >>> 12);
		return h ^ (h >>> 7) ^ (h >>> 4);
	}

	private IndexEntry readIndex(int offset) {
		byte[] data = store.get(offset, IndexEntry.LENGTH);
		IndexEntry index = new IndexEntry();
		index.fromBytes(data);
		return index;
	}

	private IndexEntry findIndex(String key) {
		int offset = offset(key);
		int hash = hash(key);
		while (true) {
			IndexEntry index = readIndex(offset);
			// 如果该index可用，说明没数据
			if (index.isAvailable()) {
				return index;
			}
			if (index.getKeyhash() == hash) {
				return index;
			}
			offset += IndexEntry.LENGTH;
		}
	}

	public IndexEntry get(String key) {
		IndexEntry index = findIndex(key);
		// 如果可用，说明没有该Index
		return index.isAvailable() ? null : index;
	}

	/**
	 * 
	 * @param key
	 * @return true 数据已成功删除。 false 没有对应的数据可删
	 */
	public IndexEntry remove(String key) {
		IndexEntry index = findIndex(key);
		if (!index.isAvailable()) {
			index.setAvailable(true);
			putIndex(index);
			return index;
		}
		return index;
	}

	public int getIndexSize() {
		return store.getRecordSize();
	}

	public void close() {
		store.close();

	}
}
